Newer
Older
BlackoutClient / Assets / Best HTTP / Source / SecureProtocol / crypto / tls / TlsExtensionsUtilities.cs
#if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
#pragma warning disable
using System;
using System.Collections;
using System.IO;

using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;

namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
{
    public abstract class TlsExtensionsUtilities
    {
        public static IDictionary EnsureExtensionsInitialised(IDictionary extensions)
        {
            return extensions == null ? BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateHashtable() : extensions;
        }

        /// <exception cref="IOException"></exception>
        public static void AddClientCertificateTypeExtensionClient(IDictionary extensions, byte[] certificateTypes)
        {
            extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes);
        }

        /// <exception cref="IOException"></exception>
        public static void AddClientCertificateTypeExtensionServer(IDictionary extensions, byte certificateType)
        {
            extensions[ExtensionType.client_certificate_type] = CreateCertificateTypeExtensionServer(certificateType);
        }

        public static void AddEncryptThenMacExtension(IDictionary extensions)
        {
            extensions[ExtensionType.encrypt_then_mac] = CreateEncryptThenMacExtension();
        }

        public static void AddExtendedMasterSecretExtension(IDictionary extensions)
        {
            extensions[ExtensionType.extended_master_secret] = CreateExtendedMasterSecretExtension();
        }

        /// <exception cref="IOException"></exception>
        public static void AddHeartbeatExtension(IDictionary extensions, HeartbeatExtension heartbeatExtension)
        {
            extensions[ExtensionType.heartbeat] = CreateHeartbeatExtension(heartbeatExtension);
        }

        /// <exception cref="IOException"></exception>
        public static void AddMaxFragmentLengthExtension(IDictionary extensions, byte maxFragmentLength)
        {
            extensions[ExtensionType.max_fragment_length] = CreateMaxFragmentLengthExtension(maxFragmentLength);
        }

        /// <exception cref="IOException"></exception>
        public static void AddPaddingExtension(IDictionary extensions, int dataLength)
        {
            extensions[ExtensionType.padding] = CreatePaddingExtension(dataLength);
        }

        /// <exception cref="IOException"></exception>
        public static void AddServerCertificateTypeExtensionClient(IDictionary extensions, byte[] certificateTypes)
        {
            extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionClient(certificateTypes);
        }

        /// <exception cref="IOException"></exception>
        public static void AddServerCertificateTypeExtensionServer(IDictionary extensions, byte certificateType)
        {
            extensions[ExtensionType.server_certificate_type] = CreateCertificateTypeExtensionServer(certificateType);
        }

        /// <exception cref="IOException"></exception>
        public static void AddServerNameExtension(IDictionary extensions, ServerNameList serverNameList)
        {
            extensions[ExtensionType.server_name] = CreateServerNameExtension(serverNameList);
        }

        public static void AddALPNExtension(IDictionary extensions, System.Collections.Generic.List<string> protocols)
        {
            extensions[ExtensionType.application_layer_protocol_negotiation] = CreateALPNExtension(protocols);
        }

        /// <exception cref="IOException"></exception>
        public static void AddStatusRequestExtension(IDictionary extensions, CertificateStatusRequest statusRequest)
        {
            extensions[ExtensionType.status_request] = CreateStatusRequestExtension(statusRequest);
        }

        public static void AddTruncatedHMacExtension(IDictionary extensions)
        {
            extensions[ExtensionType.truncated_hmac] = CreateTruncatedHMacExtension();
        }

        /// <exception cref="IOException"></exception>
        public static byte[] GetClientCertificateTypeExtensionClient(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type);
            return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static short GetClientCertificateTypeExtensionServer(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.client_certificate_type);
            return extensionData == null ? (short)-1 : (short)ReadCertificateTypeExtensionServer(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static HeartbeatExtension GetHeartbeatExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat);
            return extensionData == null ? null : ReadHeartbeatExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static short GetMaxFragmentLengthExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length);
            return extensionData == null ? (short)-1 : (short)ReadMaxFragmentLengthExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static int GetPaddingExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.padding);
            return extensionData == null ? -1 : ReadPaddingExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static byte[] GetServerCertificateTypeExtensionClient(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type);
            return extensionData == null ? null : ReadCertificateTypeExtensionClient(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static short GetServerCertificateTypeExtensionServer(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_certificate_type);
            return extensionData == null ? (short)-1 : (short)ReadCertificateTypeExtensionServer(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static ServerNameList GetServerNameExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name);
            return extensionData == null ? null : ReadServerNameExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request);
            return extensionData == null ? null : ReadStatusRequestExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static bool HasEncryptThenMacExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac);
            return extensionData == null ? false : ReadEncryptThenMacExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static bool HasExtendedMasterSecretExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.extended_master_secret);
            return extensionData == null ? false : ReadExtendedMasterSecretExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static bool HasTruncatedHMacExtension(IDictionary extensions)
        {
            byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac);
            return extensionData == null ? false : ReadTruncatedHMacExtension(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreateCertificateTypeExtensionClient(byte[] certificateTypes)
        {
            if (certificateTypes == null || certificateTypes.Length < 1 || certificateTypes.Length > 255)
                throw new TlsFatalAlert(AlertDescription.internal_error);

            return TlsUtilities.EncodeUint8ArrayWithUint8Length(certificateTypes);
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreateCertificateTypeExtensionServer(byte certificateType)
        {
            return TlsUtilities.EncodeUint8(certificateType);
        }

        public static byte[] CreateEmptyExtensionData()
        {
            return TlsUtilities.EmptyBytes;
        }

        public static byte[] CreateEncryptThenMacExtension()
        {
            return CreateEmptyExtensionData();
        }

        public static byte[] CreateExtendedMasterSecretExtension()
        {
            return CreateEmptyExtensionData();
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreateHeartbeatExtension(HeartbeatExtension heartbeatExtension)
        {
            if (heartbeatExtension == null)
                throw new TlsFatalAlert(AlertDescription.internal_error);

            MemoryStream buf = new MemoryStream();

            heartbeatExtension.Encode(buf);

            return buf.ToArray();
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreateMaxFragmentLengthExtension(byte maxFragmentLength)
        {
            return TlsUtilities.EncodeUint8(maxFragmentLength);
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreatePaddingExtension(int dataLength)
        {
            TlsUtilities.CheckUint16(dataLength);
            return new byte[dataLength];
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreateServerNameExtension(ServerNameList serverNameList)
        {
            if (serverNameList == null)
                throw new TlsFatalAlert(AlertDescription.internal_error);

            MemoryStream buf = new MemoryStream();
        
            serverNameList.Encode(buf);

            return buf.ToArray();
        }

        public static byte[] CreateALPNExtension(System.Collections.Generic.List<string> protocols)
        {
            if (protocols == null)
                throw new TlsFatalAlert(AlertDescription.internal_error);

            // https://tools.ietf.org/html/rfc7301
            using (var buf = new BestHTTP.Extensions.BufferPoolMemoryStream())
            {
                using (var protoBuf = new BestHTTP.Extensions.BufferPoolMemoryStream())
                {
                    foreach (string protocol in protocols)
                    {
                        // Empty strings MUST NOT be included and byte strings MUST NOT be truncated.
                        if (string.IsNullOrEmpty(protocol))
                            continue;

                        byte[] asciiEncoding = Strings.ToAsciiByteArray(protocol);
                        if (asciiEncoding.Length < 1)
                            throw new TlsFatalAlert(AlertDescription.internal_error);
                        TlsUtilities.WriteOpaque8(asciiEncoding, protoBuf);
                        BestHTTP.PlatformSupport.Memory.BufferPool.Release(asciiEncoding);
                    }

                    TlsUtilities.CheckUint16(protoBuf.Length);
                    TlsUtilities.WriteUint16((int)protoBuf.Length, buf);
                    protoBuf.WriteTo(buf);
                }

                return buf.ToArray();
            }
        }

        /// <exception cref="IOException"></exception>
        public static byte[] CreateStatusRequestExtension(CertificateStatusRequest statusRequest)
        {
            if (statusRequest == null)
            {
                throw new TlsFatalAlert(AlertDescription.internal_error);
            }

            MemoryStream buf = new MemoryStream();

            statusRequest.Encode(buf);

            return buf.ToArray();
        }

        public static byte[] CreateTruncatedHMacExtension()
        {
            return CreateEmptyExtensionData();
        }

        /// <exception cref="IOException"></exception>
        private static bool ReadEmptyExtensionData(byte[] extensionData)
        {
            if (extensionData == null)
                throw new ArgumentNullException("extensionData");

            if (extensionData.Length != 0)
                throw new TlsFatalAlert(AlertDescription.illegal_parameter);

            return true;
        }

        /// <exception cref="IOException"></exception>
        public static byte[] ReadCertificateTypeExtensionClient(byte[] extensionData)
        {
            byte[] certificateTypes = TlsUtilities.DecodeUint8ArrayWithUint8Length(extensionData);
            if (certificateTypes.Length < 1)
                throw new TlsFatalAlert(AlertDescription.decode_error);
            return certificateTypes;
        }

        /// <exception cref="IOException"></exception>
        public static byte ReadCertificateTypeExtensionServer(byte[] extensionData)
        {
            return TlsUtilities.DecodeUint8(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static bool ReadEncryptThenMacExtension(byte[] extensionData)
        {
            return ReadEmptyExtensionData(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static bool ReadExtendedMasterSecretExtension(byte[] extensionData)
        {
            return ReadEmptyExtensionData(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static HeartbeatExtension ReadHeartbeatExtension(byte[] extensionData)
        {
            if (extensionData == null)
                throw new ArgumentNullException("extensionData");

            MemoryStream buf = new MemoryStream(extensionData, false);

            HeartbeatExtension heartbeatExtension = HeartbeatExtension.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            return heartbeatExtension;
        }

        /// <exception cref="IOException"></exception>
        public static byte ReadMaxFragmentLengthExtension(byte[] extensionData)
        {
            return TlsUtilities.DecodeUint8(extensionData);
        }

        /// <exception cref="IOException"></exception>
        public static int ReadPaddingExtension(byte[] extensionData)
        {
            if (extensionData == null)
                throw new ArgumentNullException("extensionData");

            for (int i = 0; i < extensionData.Length; ++i)
            {
                if (extensionData[i] != 0)
                    throw new TlsFatalAlert(AlertDescription.illegal_parameter);
            }
            return extensionData.Length;
        }

        /// <exception cref="IOException"></exception>
        public static ServerNameList ReadServerNameExtension(byte[] extensionData)
        {
            if (extensionData == null)
                throw new ArgumentNullException("extensionData");

            MemoryStream buf = new MemoryStream(extensionData, false);

            ServerNameList serverNameList = ServerNameList.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            return serverNameList;
        }

        /// <exception cref="IOException"></exception>
        public static CertificateStatusRequest ReadStatusRequestExtension(byte[] extensionData)
        {
            if (extensionData == null)
                throw new ArgumentNullException("extensionData");

            MemoryStream buf = new MemoryStream(extensionData, false);

            CertificateStatusRequest statusRequest = CertificateStatusRequest.Parse(buf);

            TlsProtocol.AssertEmpty(buf);

            return statusRequest;
        }

        /// <exception cref="IOException"></exception>
        public static bool ReadTruncatedHMacExtension(byte[] extensionData)
        {
            return ReadEmptyExtensionData(extensionData);
        }
    }
}
#pragma warning restore
#endif